package com.gm.census.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.QueryResultIterator;

@Controller
@RequestMapping("/test")
public class TestController {

	private static final String CHILD = "Child";

	private DatastoreService ds() {
		return DatastoreServiceFactory.getDatastoreService();
	}

	private Key parent() {
		DatastoreService ds = ds();
		Key k = KeyFactory.createKey("Parent", "parent");
		try {
			return ds.get(k).getKey();
		} catch (EntityNotFoundException e) {
			return ds.put(new Entity(k));
		}
	}

	private Entity child(String name, Date created) {
		Entity e = new Entity(CHILD, parent());
		e.setProperty("name", name);
		e.setUnindexedProperty("created", created);
		return e;
	}

	private Query query() {
		Query q = new Query(CHILD, parent());
		q.addSort("name");
		return q;
	}

	@RequestMapping(method = RequestMethod.GET)
	public String list(Model m,
			@RequestParam(value = "cursor", required = false) String cursor) {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		PreparedQuery pq = ds().prepare(query());
		if (cursor != null && cursor.length() > 0)
			pq.asQueryResultIterable(FetchOptions.Builder
					.withStartCursor(Cursor.fromWebSafeString(cursor)));

		QueryResultIterator<Entity> it = pq.asQueryResultIterator();
		while (it.hasNext()) {
			Entity e = it.next();
			Map<String, Object> props = new HashMap<String, Object>();
			props.putAll(e.getProperties());
			props.put("id", KeyFactory.keyToString(e.getKey()));
			props.put("cursor", it.getCursor().toWebSafeString());
			list.add(props);
		}
		m.addAttribute("children", list);
		return "test/list";
	}

	@RequestMapping(method = RequestMethod.PUT)
	public String put(Model m, @RequestParam("name") String name) {
		DatastoreService ds = ds();
		m.addAttribute("child",
				KeyFactory.keyToString(ds.put(child(name, new Date()))));
		return list(m,null);
	}

	@RequestMapping(value = "/{id}", method = RequestMethod.POST)
	public String update(Model m, @PathVariable("id") String id,
			@RequestParam("name") String name) throws EntityNotFoundException {
		DatastoreService ds = ds();
		Entity e = ds.get(KeyFactory.stringToKey(id));
		e.setProperty("name", name);
		m.addAttribute("child", KeyFactory.keyToString(ds.put(e)));
		return list(m,null);
	}

	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
	public String delete(Model m, @PathVariable("id") String id) {
		DatastoreService ds = ds();
		ds.delete(KeyFactory.stringToKey(id));
		return list(m,null);
	}

	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public String get(Model m, @PathVariable("id") String id)
			throws EntityNotFoundException {
		DatastoreService ds = ds();
		Entity e = ds.get(KeyFactory.stringToKey(id));
		m.addAttribute("child", e.getProperties());
		return "test/get";
	}

	@RequestMapping(value = "/list/{ent}", method = RequestMethod.GET)
	public String listEnt(Model m, @PathVariable("ent") String ent,
			@RequestParam(value = "cursor", required = false) String cursor)
			throws EntityNotFoundException {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		PreparedQuery pq = ds().prepare(new Query(ent));
		if (cursor != null && cursor.length() > 0)
			pq.asQueryResultIterable(FetchOptions.Builder
					.withStartCursor(Cursor.fromWebSafeString(cursor)));

		QueryResultIterator<Entity> it = pq.asQueryResultIterator();
		while (it.hasNext()) {
			Entity e = it.next();
			Map<String, Object> props = new HashMap<String, Object>();
			props.putAll(e.getProperties());
			props.put("id", KeyFactory.keyToString(e.getKey()));
			props.put("cursor", it.getCursor().toWebSafeString());
			list.add(props);
		}
		m.addAttribute("ents", list);
		return "test/entlist";
	}
}
